package com.atlc.preview.project.net.client;

import com.atlc.preview.project.model.Examine;
import com.atlc.preview.project.model.Pages;
import com.atlc.preview.project.model.Problem;
import com.atlc.preview.project.utils.FileAnalyseUtils;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.List;
import java.util.Timer;
import java.util.*;


/**
 * @author 梁冲
 * @version 1.0
 * @email 1357042069@qq.com
 * @date 2021/12/01
 */
public class Client {

    private Socket socket;

    private String examineInfo;

    private Pages pages;

    private int status = 001;

    private String msg;

    private int totalScore = -1;

    private StringBuilder builder = new StringBuilder();

    private String responseCode;

    private String[] answersCache;

    private boolean submit = false;

    public long time = 3600;

    public Client(int port) {
        initFrame();
        initClient(port);
    }

    private void initFrame() {
        try {
            new LoginFrame();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void initClient(int port) {
        String serverName = "localhost";
        try {
            this.socket = new Socket(serverName, port);
            if (socket.isConnected()) {
                Handler thread = new Handler(socket);
                thread.run();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public boolean doRead(InputStream in) {
        if (socket.isClosed()) {
            return false;
        }
        byte[] bytes = new byte[1024 * 1024];
        try {
            in.read(bytes);
            responseCode = new String(bytes).trim();
            String code = responseCode.substring(0, 3);
            if ("102".equals(code)) {
                String[] msg = responseCode.split(" ");
                if ("0".equals(msg[1])) {
                    System.out.println(msg[2]);
                    return true;
                }
            } else if ("103".equals(code)) {
                status = 005;
                String params = responseCode.substring(4);
                String[] split = params.split("@");
                pages = FileAnalyseUtils.getPages(Arrays.asList(split));
                JOptionPane.showMessageDialog(new JLabel(), "成功接收试卷");
            } else if ("104".equals(code)) {
                System.out.println("接收到来自服务端的消息："+responseCode.split(" ")[2]);
                status = 005;
            } else if ("105".equals(code)) {
                System.out.println(responseCode.split(" ")[2]);
            }
            else if ("106".equals(code)) {
                submit = true;
                status = 000;
                String s = responseCode.split(" ")[2];
                System.out.println(s);
                JOptionPane.showMessageDialog(new JLabel(), responseCode.split(" ")[2]);
            } else if ("107".equals(code)) {
                status = 005;
                String[] params = responseCode.split("~");
                answersCache = params[2].split(" ");
                time = Integer.parseInt(params[3]);
                pages = FileAnalyseUtils.getPages(Arrays.asList(params[1].split("@")));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return true;
    }

    private boolean doWrite(OutputStream out) {
        if (socket.isClosed()) {
            return false;
        }
        try {
            System.out.println(status);
            switch (status) {
                case 001:
                    doAuthentication(out);
                    break;
                case 002:
                    doRequestPages(out);
                    break;
                case 003:
                    doUpdateInfo(out);
                    break;
                case 005:
                    doHeartBeat(out);
                    break;
                case 006:
                    doSendResult(out);
                    break;
                default:
                    System.out.println("已经与服务端断开连接！");
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return true;
    }

    private void doSendResult(OutputStream out) throws IOException {
        if (totalScore == -1) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("客户端向服务端传输考试结果！");
        out.write(("006 " + totalScore + " 传输最后考试结果").getBytes());
        out.flush();
    }

    private void doUpdateInfo(OutputStream out) throws IOException {
        System.out.println("builder的大小"+builder);
        out.write(("003 " + builder.toString()).getBytes());
        out.flush();
    }

    private void doRequestPages(OutputStream out) throws IOException {
        while (true) {
            if (msg != null) {
                break;
            }
        }
        out.write(msg.getBytes());
        out.flush();
    }

    private void doHeartBeat(OutputStream out) throws IOException {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(time);
        out.write(("005 "+time+" 请求验证").getBytes());
        out.flush();
    }

    private void doAuthentication(OutputStream out) throws IOException {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 如果这时候还没来消息
        if (examineInfo == null) {
            out.write("001 null@null@null 马上将会发起身份验证".getBytes());
            out.flush();
            return;
        }
        out.write(msg.getBytes());
        out.flush();
    }

    private class Handler implements Runnable {

        private Socket socket;

        public Handler(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            OutputStream out;
            InputStream in;
            System.out.println("Begin to Chat to server...");
            try {
                out = socket.getOutputStream();
                in = socket.getInputStream();
                if (socket.isConnected()) {
                    while (true) {
                        if (socket.isConnected()) {
                            if (!submit && status != 000) {
                                doWrite(out);
                                System.out.println("begin read message from server.");
                                doRead(in);
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    class LoginFrame extends JFrame {

        private JLabel JLTitle1 = new JLabel("欢迎来到考试系统");

        private JLabel JLTitle2 = new JLabel("请考生填写下列信息");


        private JLabel JLName = new JLabel("姓名： ");
        private JLabel JLIdentity = new JLabel("身份证：");
        private JLabel JLId = new JLabel("学号： ");

        private JTextField JTName = new JTextField(15);
        private JTextField JTId = new JTextField(15);
        private JTextField JTIdentity = new JTextField(15);

        private JButton JBStart = new JButton("开始考试");

        private JPanel JPTop = new JPanel();
        private JPanel JP1 = new JPanel();

        private JPanel JP2 = new JPanel();

        private JPanel JP3 = new JPanel();

        private JPanel JP4 = new JPanel();

        private JPanel JPCenter = new JPanel();

        private JPanel JPBottom = new JPanel();

        // 构造函数 ==> 设置窗口，布局标签并将其显示在窗口
        public LoginFrame() throws Exception {
            this.setTitle("JAVA-考试系统");
            this.setSize(500, 450);
            // 将窗口置于屏幕的中心
            this.setLocationRelativeTo(null);
            // BorderLayout（边界布局），第一个参数横向间距，第二个参数横向间距
            this.setLayout(new BorderLayout(0, 20));

            JLTitle1.setFont(new Font("黑体", Font.BOLD, 35));
            JLTitle1.setForeground(Color.blue);
            JPTop.add(JLTitle1);
            JPTop.setLayout(new GridBagLayout());
            this.add(JPTop, BorderLayout.NORTH);

            JLTitle2.setFont(new Font("黑体", Font.BOLD, 25));
            JLTitle2.setForeground(Color.red);
            JP1.add(JLTitle2);

            JLName.setFont(new Font("黑体", Font.BOLD, 15));
            JP2.add(JLName);
            JP2.add(JTName);

            JLId.setFont(new Font("黑体", Font.BOLD, 15));
            JP3.add(JLIdentity);
            JP3.add(JTIdentity);

            JLIdentity.setFont(new Font("黑体", Font.BOLD, 15));
            JP4.add(JLId);
            JP4.add(JTId);

            JPCenter.add(JP1);
            JPCenter.add(JP2);
            JPCenter.add(JP3);
            JPCenter.add(JP4);
            JPCenter.setLayout(new GridLayout(4, 1));// GridLayout（网格布局）
            this.add(JPCenter, BorderLayout.CENTER);
            JPCenter.setBorder(BorderFactory.createLoweredBevelBorder());
            JPBottom.add(JBStart);
            this.add(JPBottom, BorderLayout.SOUTH);
            Warn();
            this.setVisible(true);
        }

        // 规范文本，弹出提示框
        private void Warn() {
            JBStart.addActionListener(e -> {
                if ("".equals(JTName.getText()) || "".equals(JTIdentity.getText()) || "".equals(JTId.getText())) {
                    JOptionPane.showMessageDialog(null, "请输入完整信息", "提示", JOptionPane.ERROR_MESSAGE);
                } else {
                    String id = JTId.getText();
                    String name = JTName.getText();
                    String identity = JTIdentity.getText();
                    examineInfo = id + "@" + name + "@" + identity;
                    msg = "001" + " " + examineInfo + " " + "请求身份验证";
                    status = 001;
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException interruptedException) {
                        interruptedException.printStackTrace();
                    }
                    if (responseCode != null) {
                        String statusCode = responseCode.substring(0, 3);
                        if ("101".equals(statusCode)) {
                            String[] s = responseCode.split(" ");
                            if ("1".equals(s[1])) {
                                JOptionPane.showMessageDialog(new JLabel(), s[2]);
                                new Notes();
                                dispose();
                            } else {
                                JOptionPane.showMessageDialog(new JLabel(), s[2]);
                            }
                        } else if ("107".equals(statusCode)) {
                            new TestFrame();
                            dispose();
                        }
                    }
                }
            });
        }
    }

    class Notes extends JFrame {

        public Notes() {
            initialize();
        }

        private void initialize() {
            this.setTitle("\u8003\u8BD5\u987B\u77E5");
            this.setBounds(200, 200, 800, 600);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.getContentPane().setLayout(null);
            this.setVisible(true);

            JLabel label1 = new JLabel("Java\u57FA\u7840\u77E5\u8BC6\u6D4B\u8BD5");
            label1.setForeground(new Color(109, 126, 86));
            label1.setFont(new Font("幼圆", Font.PLAIN, 40));
            label1.setBounds(235, 10, 330, 80);
            this.getContentPane().add(label1);

            JLabel label2 = new JLabel("\u8003\u8BD5\u987B\u77E5");
            label2.setFont(new Font("幼圆", Font.PLAIN, 30));
            label2.setForeground(new Color(109, 126, 86));
            label2.setBounds(340, 100, 200, 60);
            this.getContentPane().add(label2);

            JLabel label3 = new JLabel("1. 考试时间60分钟,时间结束自动提交试卷.");
            label3.setFont(new Font("幼圆", Font.PLAIN, 19));
            label3.setBounds(180, 220, 500, 40);
            label3.setForeground(new Color(109, 126, 86));
            this.getContentPane().add(label3);

            JLabel label4 = new JLabel("2. 完成题目后请仔细检查答案.");
            label4.setFont(new Font("幼圆", Font.PLAIN, 19));
            label4.setBounds(180, 270, 500, 40);
            label4.setForeground(new Color(109, 126, 86));
            this.getContentPane().add(label4);

            JLabel label5 = new JLabel("3. 确认无误后请点击提交试卷,系统计算后会显示本次测试分数.");
            label5.setFont(new Font("幼圆", Font.PLAIN, 19));
            label5.setBounds(180, 320, 600, 40);
            label5.setForeground(new Color(109, 126, 86));
            this.getContentPane().add(label5);

            JButton button = new JButton("\u5F00\u59CB\u8003\u8BD5");
            button.setFont(new Font("幼圆", Font.PLAIN, 35));
            button.setBounds(300, 420, 200, 50);
            button.setForeground(new Color(109, 126, 86));
            this.getContentPane().add(button);

            button.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    //进入考试界面
                    msg = "002" + " " + "@" + " " + "请求试卷下载";
                    status = 002;
                    while (true) {
                        if (pages != null) {
                            new TestFrame();
                            dispose();
                            break;
                        }
                    }
                }
            });
        }

    }

    class TestFrame extends JFrame {

        private ButtonGroup[] box = new ButtonGroup[pages.getProblemList().size()];

        private int count = 1;

        private JPanel JPTop = new JPanel();
        private JPanel JPCenter = new JPanel();
        private JPanel JPBottom = new JPanel();

        private JPanel[] singleQuestion = new JPanel[pages.getProblemList().size()];

        private List<Problem> allProblems = pages.getProblemList();
        // 页数
        private JLabel JLAllPage = new JLabel();
        private JLabel JLChangePage = new JLabel();
        // 页码控制
        private JLabel JLTime = new JLabel("  倒计时:");
        private JLabel JLHour = new JLabel();
        private JLabel JLMinute = new JLabel();
        private JLabel JLSeconds = new JLabel();

        private JButton JBOverTest = new JButton("提交考卷");

        private JButton JBUpdate = new JButton("实时更新答题状态");

        private JButton JBFirst = new JButton("首页");
        private JButton JBPrevious = new JButton("上一页");
        private JButton JBNext = new JButton("下一页");
        private JButton JBLast = new JButton("尾页");

        private CardLayout cardLayout = new CardLayout(); // 卡片布局

        private Font font = new Font("微软雅黑", Font.BOLD, 25);


        /**
         * 无参构造
         *
         * @throws Exception
         */
        public TestFrame() {
            this.setTitle("面向对象程序设计技术（Java）单元测试试卷");
            this.setSize(1500, 800);
            //将此窗口置于屏幕的中央
            this.setLocationRelativeTo(null);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            //设置 各组件间水平垂直间隔为20像素
            this.setLayout(new BorderLayout(20, 20));

            JLChangePage.setText("第" + count + "页");

            JLChangePage.setFont(font);
            JLAllPage.setFont(font);
            JLMinute.setFont(font);
            JLSeconds.setFont(font);
            JLHour.setFont(font);
            JLTime.setFont(font);
            JBLast.setFont(font);
            JBFirst.setFont(font);
            JBNext.setFont(font);
            JBPrevious.setFont(font);
            JBOverTest.setFont(font);
            JBUpdate.setFont(font);

            JPTop.setLayout(new FlowLayout());
            JPTop.add(JLAllPage);
            JPTop.add(JLChangePage);
            JPTop.add(JLTime);
            JPTop.add(JLHour);
            JPTop.add(JLMinute);
            JPTop.add(JLSeconds);
            JPTop.add(JBOverTest);
            this.add(JPTop, BorderLayout.NORTH);

            JPCenter.setLayout(cardLayout);
            this.add(JPCenter, BorderLayout.CENTER);
            JPCenter.setBorder(BorderFactory.createLoweredBevelBorder());

            JPBottom.setLayout(new GridLayout(1, 4));
            JPBottom.add(JBFirst);
            JPBottom.add(JBPrevious);
            JPBottom.add(JBNext);
            JPBottom.add(JBLast);
            this.add(JPBottom, BorderLayout.SOUTH);

            loadPaper();
            overTest();
            setVisible(true);
        }

        //    加载试卷
        private void loadPaper() {
            int i = 0, k = 0;
            boolean flag = false;
            if (answersCache != null) {
                flag = true;
            }
            for (Problem problem : allProblems) {  // 15页
                singleQuestion[i] = new JPanel(new GridLayout(6, 1, 0, 0));

                JLabel title, type; // 题目标签
                JRadioButton[] select = new JRadioButton[4]; // 每到题总共4个选项
                JCheckBox[] select1 = new JCheckBox[4]; // 每到题总共4个选项

                title = new JLabel(problem.getTitle()); // lab是题目，放入p中
                type = new JLabel("，每题");
                title.setFont(font);
                type.setFont(font);
                singleQuestion[i].add(type);
                singleQuestion[i].add(title);
                String ans = "";
                if (flag) {
                    ans = answersCache[i];
                }
                // 单选
                if ("单选题".equals(problem.getType())) {
                    type.setText(problem.getType() + type.getText() + problem.getScore().toString() + "分");
                    box[k] = new ButtonGroup();// 将4个选项放在同一个"盒子"，实现单选效果
                    String[] chooses = problem.getChooses().toArray(new String[0]);
                    for (int j = 0; j < 4; j++) {
                        // 每道题包含 题目+4个选项
                        select[j] = new JRadioButton(chooses[j]);
                        select[j].setFont(new Font("微软雅黑", Font.BOLD, 25));
                        box[k].add(select[j]);
                        singleQuestion[i].add(select[j]);
                    }
                    if ("A".equals(ans)) {
                        select[0].setSelected(true);
                    } else if ("B".equals(ans)) {
                        select[1].setSelected(true);
                    } else if ("C".equals(ans)) {
                        select[2].setSelected(true);
                    } else if ("D".equals(ans)) {
                        select[3].setSelected(true);
                    }
                }
                // 多选
                else if ("多选题".equals(problem.getType())) {
                    type.setText(problem.getType() + type.getText() + problem.getScore().toString() + "分");
                    String[] chooses = problem.getChooses().toArray(new String[0]);
                    for (int j = 0; j < 4; j++) {
                        select1[j] = new JCheckBox(chooses[j]);
                        select1[j].setFont(font);
                        singleQuestion[i].add(select1[j]);
                    }
                    for (int index = 0; index < ans.length(); index++) {
                        char ch = ans.charAt(index);
                        if (ch == 'A') {
                            select1[0].setSelected(true);
                        } else if (ch == 'B') {
                            select1[1].setSelected(true);
                        } else if (ch == 'C') {
                            select1[2].setSelected(true);
                        } else if (ch == 'D') {
                            select1[3].setSelected(true);
                        }
                    }
                }
                // 判断
                else {
                    type.setText(problem.getType() + type.getText() + problem.getScore().toString() + "分");
                    box[k] = new ButtonGroup();
                    String[] chooses = problem.getChooses().toArray(new String[0]);
                    for (int j = 0; j < 2; j++) {
                        select[j] = new JRadioButton(chooses[j]);
                        select[j].setFont(font);
                        box[k].add(select[j]);
                        singleQuestion[i].add(select[j]);
                    }
                    if ("A".equals(ans)) {
                        select[0].setSelected(true);
                    } else if ("B".equals(ans)) {
                        select[1].setSelected(true);
                    }
                    k++;
                }
                JPCenter.add(singleQuestion[i]);
                i++;
            }
            time();
        }

        //     实现页面跳转 + 提交试卷按钮 ==> 获取成绩
        private void overTest() {
            //提交试卷按钮
            JBOverTest.addActionListener(e -> {
                if (e.getSource() == JBOverTest) {
                    int grade = 0, i = 0, total_grade = 0, right = 0;
                    for (Problem problem : pages.getProblemList()) {
                        // 单选题打分
                        if (problem.getType().equals("单选题")) {
                            total_grade += problem.getScore();
                            StringBuilder selfAnswer = new StringBuilder();
                            Component[] components = singleQuestion[i].getComponents();
                            for (Component component : components) {
                                if (component.getClass().equals(JLabel.class))
                                    continue;
                                JRadioButton jcb = (JRadioButton) component;
                                if (jcb.isSelected()) {
                                    selfAnswer.append(jcb.getText().subSequence(0, 1));
                                }
                            }
                            if (problem.getAnswer().equals(selfAnswer.toString())) {
                                grade += problem.getScore();
                                right++;
                            }
                        } else if (problem.getType().equals("多选题")) {
                            total_grade += problem.getScore();
                            StringBuilder selfAnswer = new StringBuilder();
                            Component[] components = singleQuestion[i].getComponents();
                            for (Component component : components) {
                                if (component.getClass().equals(JLabel.class))
                                    continue;
                                JCheckBox jcb = (JCheckBox) component;
                                if (jcb.isSelected()) {
                                    selfAnswer.append(jcb.getText().subSequence(0, 1));
                                }
                            }
                            if (problem.getAnswer().equals(selfAnswer.toString())) {
                                grade += problem.getScore();
                                right++;
                            }
                        } else {
                            total_grade += problem.getScore();
                            StringBuilder selfAnswer = new StringBuilder();
                            Component[] components = singleQuestion[i].getComponents();
                            for (Component component : components) {
                                if (component.getClass().equals(JLabel.class))
                                    continue;
                                JRadioButton jcb = (JRadioButton) component;
                                if (jcb.isSelected()) {
                                    selfAnswer.append(jcb.getText().subSequence(0, 1));
                                }
                            }
                            if (problem.getAnswer().equals(selfAnswer.toString())) {
                                grade += problem.getScore();
                                right++;
                            }
                        }
                        i++;
                    }
                    totalScore = right;
                    status = 006;
                    dispose();
                }
            });
            JBUpdate.addActionListener(e -> {
                status = 003;
                builder.delete(0, builder.length());
                for (int i = 0; i < allProblems.size(); i++) {
                    Component[] components = singleQuestion[i].getComponents();
                    boolean choose = false;
                    for (Component component : components) {
                        if (component.getClass().equals(JLabel.class))
                            continue;
                        if (component instanceof JRadioButton) {
                            JRadioButton jcb = (JRadioButton) component;
                            if (jcb.isSelected()) {
                                choose = true;
                                char c = jcb.getText().charAt(0);
                                builder.append(c);
                            }
                        } else {
                            JCheckBox jcb = (JCheckBox) component;
                            if (jcb.isSelected()) {
                                choose = true;
                                char c = jcb.getText().charAt(0);
                                builder.append(c);
                            }
                        }
                    }
                    if (!choose) {
                        builder.append("@");
                    }
                    builder.append(" ");
                }
                System.out.println(builder);
            });

            //首页
            JBFirst.addActionListener(e -> {
                cardLayout.first(JPCenter);  // JPCenter一共15页，first返回第一页（实现页数跳转）
                count = 1;
                JLChangePage.setText("第" + count + "页");
            });

            //前一页
            JBPrevious.addActionListener(e -> {
                cardLayout.previous(JPCenter);
                if (count > 1 && count <= allProblems.size()) {
                    count--;
                } else {
                    count = allProblems.size();
                }
                JLChangePage.setText("第" + count + "页");
            });

            //下一页
            JBNext.addActionListener(e -> {
                cardLayout.next(JPCenter);
                if (count >= 1 && count < 15) {
                    count++;
                } else {
                    count = 1;
                }
                JLChangePage.setText("第" + count + "页");
            });

            //尾页
            JBLast.addActionListener(e -> {
                JBUpdate.doClick();
                cardLayout.last(JPCenter);
                count = pages.getProblemList().size();
                JLChangePage.setText("第" + count + "页");
            });
        }

        //     定时器
        private void time() {
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    time--;
                    long hour = time / 3600;
                    long minute = (time - hour * 3600) / 60;
                    long seconds = time - hour * 3600 - minute * 60;
                    JLHour.setText(hour + "时");
                    JLMinute.setText(minute + "分");
                    JLSeconds.setText(seconds + "秒");
                    if (seconds % 20 == 0 && !submit) {
                        JBUpdate.doClick();
                    }
                    if (time == 0) {
                        JBOverTest.doClick(); // 自动点击“提交试卷”按钮
                    }
                }
            }, 0, 1000);  // 延时0秒触发，以后每间隔1秒循环触发
        }  // 延时0秒触发，以后每间隔1秒循环触发
    }

    public static void main(String[] args) {
        new Client(8010);
    }
}
